《Android Framework 之路》BootAnimation(1)

介绍

开机动画,BootAnimation,就是Android手机开机郭晨各种以一个展示给用户的界面,实际是一个多个帧组成的动画,在界面上进行一帧一帧的播放,形成开机动画的效果。
本文针对Android5.1源码分析BootAnimation

源码分析

文件产生

Android平台的开机动画由system/bin下的bootanimation文件完成,而这个文件产生于
frameworks/base/cmds/bootanimation/Android.mk

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
bootanimation_main.cpp \
AudioPlayer.cpp \
BootAnimation.cpp

LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES

LOCAL_C_INCLUDES += external/tinyalsa/include

LOCAL_SHARED_LIBRARIES := \
libcutils \
liblog \
libandroidfw \
libutils \
libbinder \
libui \
libskia \
libEGL \
libGLESv1_CM \
libgui \
libtinyalsa

LOCAL_MODULE:= bootanimation

ifdef TARGET_32_BIT_SURFACEFLINGER
LOCAL_32_BIT_ONLY := true
endif
include $(BUILD_EXECUTABLE)

编译结果为bootanimation的bin文件,所以,在有足够权限的前提下,在adb shell下执行bootanimation也是可以看到对应的开机动画效果的。

启动开机动画

开机动画是以bin文件的形式存在于手机系统中,开机过程中通过init.rc定义
system/core/rootdir/init.rc

1
2
3
4
5
6
service bootanim /system/bin/bootanimation
class core
user graphics
group graphics audio
disabled//定义了disable,在开机过程中不会自动的启动
oneshot

这里不会启动,那么在哪里启动? 由于开机动画对SurfaceFlinger有依赖,所以应该是在SurfaceFlinger启动之后再开始执行,看一下源码。

SurfaceFlinger的启动在init.rc文件中

1
2
3
4
5
service surfaceflinger /system/bin/surfaceflinger
class core
user system
group graphics drmrpc
onrestart restart zygote

与SurfaceFlinger相关的源码存在于
frameworks\native\services\surfaceflinger
入口
frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#if defined(HAVE_PTHREADS)
#include <sys/resource.h>
#endif

#include <cutils/sched_policy.h>
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include "SurfaceFlinger.h"

using namespace android;

int main(int, char**) {
// When SF is launched in its own process, limit the number of
// binder threads to 4.
ProcessState::self()->setThreadPoolMaxThreadCount(4);

// start the thread pool
sp<ProcessState> ps(ProcessState::self());
ps->startThreadPool();

// instantiate surfaceflinger
sp<SurfaceFlinger> flinger = new SurfaceFlinger();

#if defined(HAVE_PTHREADS)
setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY);
#endif
set_sched_policy(0, SP_FOREGROUND);

// initialize before clients can connect
flinger->init();//开机动画在这里执行,接着往下看

// publish surface flinger
sp<IServiceManager> sm(defaultServiceManager());
sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false);

// run in this thread
flinger->run();

return 0;
}

frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

1
2
3
4
5
6
7
void SurfaceFlinger::init() {
ALOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
....
// start boot animation
startBootAnim();
}

接着执行startBootAnim();

1
2
3
4
5
void SurfaceFlinger::startBootAnim() {
// start boot animation
property_set("service.bootanim.exit", "0");
property_set("ctl.start", "bootanim");
}

这里采用的是通过property_set中”ctl.start”的方式执行bootanim,这里是通过设置属性值的方式来启动的,属性值的设置采用的是C/S模式,socket连接,这里不详述,大致说下,这行代码会执行到

system/core/init/property_service.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
void handle_property_set_fd()
{
......
switch(msg.cmd) {
case PROP_MSG_SETPROP:
......
//这里很关键
if(memcmp(msg.name,"ctl.",4) == 0) {
// Keep the old close-socket-early behavior when handling
// ctl.* properties.
close(s);
if (check_control_mac_perms(msg.value, source_ctx)) {
handle_control_message((char*) msg.name + 4, (char*) msg.value);
} else {
ERROR("sys_prop: Unable to %s service ctl [%s] uid:%d gid:%d pid:%d\n",
msg.name + 4, msg.value, cr.uid, cr.gid, cr.pid);
}
//这里很关键
} else {
if (check_perms(msg.name, source_ctx)) {
property_set((char*) msg.name, (char*) msg.value);
} else {
ERROR("sys_prop: permission denied uid:%d name:%s\n",
cr.uid, msg.name);
}

// Note: bionic's property client code assumes that the
// property server will not close the socket until *AFTER*
// the property is written to memory.
close(s);
}
freecon(source_ctx);
break;

default:
close(s);
break;
}
}

接下来执行到
system/core/init/init.c

1
2
3
4
5
6
7
8
9
10
11
12
void handle_control_message(const char *msg, const char *arg)
{
if (!strcmp(msg,"start")) {
msg_start(arg);//就是这条路
} else if (!strcmp(msg,"stop")) {
msg_stop(arg);
} else if (!strcmp(msg,"restart")) {
msg_restart(arg);
} else {
ERROR("unknown control msg '%s'\n", msg);
}
}

接着往下执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
static void msg_start(const char *name)
{
struct service *svc = NULL;
char *tmp = NULL;
char *args = NULL;

if (!strchr(name, ':'))
svc = service_find_by_name(name);
else {
tmp = strdup(name);
if (tmp) {
args = strchr(tmp, ':');
*args = '\0';
args++;

svc = service_find_by_name(tmp);
}
}

if (svc) {
service_start(svc, args);
} else {
ERROR("no such service '%s'\n", name);
}
if (tmp)
free(tmp);
}

这里找到“bootanim”然后执行service_start函数,这里就是启动bootanim的地方。

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×